package com.dapeis.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import tk.mybatis.mapper.common.example.oper.OperBuilder;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

import com.ag.core.exception.EntityNotFoundException;
import com.ag.core.exception.InvalidParamException;
import com.ag.core.exception.SysTipsException;
import com.ag.core.utils.AgAssert;
import com.ag.dao.DBService;
import com.ag.dao.IDao;
import com.ag.module.common.api.service.AbstractUserService;
import com.ag.module.common.api.service.FileService;
import com.ag.module.common.api.service.NoticePushService;
import com.ag.module.common.api.service.SequenceService;
import com.ag.utils.AlgorithmEnum;
import com.ag.utils.AlgorithmUtils;
import com.ag.utils.NumberUtils;
import com.dapeis.core.utils.StylistConstants;
import com.dapeis.dao.IUserExtMapper;
import com.dapeis.dao.IUserMapper;
import com.dapeis.domain.User;
import com.dapeis.domain.UserInformation;
import com.dapeis.domain.UserThirdPartyLogin;
import com.dapeis.domain.ext.UserExt;
import com.dapeis.exception.user.UserContactNotFoundException;
import com.dapeis.exception.user.UserExistContactException;
import com.dapeis.exception.user.UserNotFoundException;
import com.dapeis.exception.user.UserStateDisableException;

/**
 * 
 * Title:UserService.java UserService Description:
 * 
 * @author yuanyong
 * @date 2017年4月19日 下午1:46:55 Email: hzyuanyong@126.com
 *
 */
@Service
public class UserService extends DBService<User> implements AbstractUserService {
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    IUserMapper mapper;

    protected final static String SEQUENCE_USER_ID_KEY = "userId";
    public static final String DEFAULT_HEAD_NAME = "匿名用户";
    public static final String DEFAULT_HEAD_IMG = "resources/user_default.png";
    public final static Pattern mobilePhonePattern = Pattern
	    .compile("\\d{6,11}");

    @Resource
    CachingConfigurer cachingConfigurer;
    @Resource
    FileService fileService;
    @Resource
    SequenceService sequenceService;
    @Resource
    NoticePushService noticePushService;
    @Resource
    UserThirdPartyLoginService userThirdPartyLoginService;
    @Resource
    UserInformationService userInformationService;
    @Resource
    IUserExtMapper userExtMapper;
    @Resource
    TIMService timService;

    /**
     * 根据Id查找状态
     * 
     * @param userId
     */
    public void checkUserVaild(Integer userId) {
	this.checkUserVaild(getUserByUserId(userId));
    }

    /**
     * 查找状态
     * 
     * @param user
     */
    public void checkUserVaild(User user) {
	if (user == null) {
	    throw new UserNotFoundException();
	}
	if (user.getState() != StylistConstants.State.NORMAL) {
	    throw new UserStateDisableException();
	}
    }

    /**
     * 更新缓存
     */
    @Override
    public int updateByPrimaryKey(User record) {
	whenUserUpdate(record.getId());
	return super.updateByPrimaryKey(record);
    }

    /**
     * 更新用户
     */
    @Override
    public int updateByPrimaryKeySelective(User record) {
	whenUserUpdate(record.getId());
	return super.updateByPrimaryKeySelective(record);
    }

    public int updateFrontLogin(User record) {
	return super.updateByPrimaryKeySelective(record);
    }

    // @CacheEvict(value =
    // RedisJdkSerializationCacheManagerRegist.CACHE_REDIS_JDK_SER, key =
    // "'_user_' + #userId")
    private boolean whenUserUpdate(Integer userId) {
	Cache cache = cachingConfigurer.cacheManager().getCache("user");
	cache.evict("_user_" + userId);
	return true;
    }

    public int getUserContactTotalCount() {
	return selectCount(null);
    }

    @Cacheable(value = "user", key = "'_user_' + #userId")
    public User getUserByUserId(Integer userId) {
	User userDB = selectByPrimaryKey(userId);
	return userDB;
    }

    /**
     * 根据手机号查找用户
     * 
     * @param contact
     * @return
     */
    public User getUserByContact(String contact) {
	Example example = example();
	example.createCriteria().andEqualTo("contact", contact);
	return selectOneByExample(example);
    }

    /**
     * 根据微信openId查找用户
     * 
     * @param openId
     * @return
     */
    public User getUserByWeixinOpenId(String openId) {
	UserThirdPartyLogin userSourceByWeixin = userThirdPartyLoginService
		.getWxUserThirdPartyLogin(openId);
	if (userSourceByWeixin == null) {
	    // 兼容后续
	    Example example = new Example(User.class);
	    example.createCriteria().andEqualTo(User.PROPERTY_OPENSOURCEKEY,
		    openId);
	    List<User> list = selectByExample(example);
	    if (null == list || list.isEmpty())
		return null;
	    return list.get(0);
	}

	return selectByPrimaryKey(userSourceByWeixin.getUserId());
    }

    /**
     * 判断用户是否绑定了手机
     * 
     * @param userId
     * @return true 已经绑定 false 未绑定
     */
    public boolean isBindMobilePhoneNumber(Integer userId) {
	User user = selectByPrimaryKey(userId);
	return isBindMobilePhoneNumber(user);
    }

    /**
     * 判断是否绑定了手机号码
     * 
     * @param user
     * @return true-已经绑定 false-未绑定
     */
    public boolean isBindMobilePhoneNumber(User user) {
	return null != user && StringUtils.isNotBlank(user.getContact())
		&& mobilePhonePattern.matcher(user.getContact()).matches();
    }

    /**
     * 获取用户全部信息
     * 
     * @param openId
     * @return
     */
    public UserExt getUserInfoExt(String openId) {
	User user = getUserByWeixinOpenId(openId);
	UserInformation userInformation = userInformationService
		.getUserInformationByUserId(user.getId());
	UserExt uExt = new UserExt();
	uExt.setUserInformation(userInformation);
	return uExt;
    }

    /**
     * 根据用户ID绑定手机
     * 
     * @param userId
     * @param contact
     * @return
     */
    public boolean bindMobilePhoneNumber(Integer userId, String contact) {
	AgAssert.isTrue(StringUtils.isNotBlank(contact)
		&& mobilePhonePattern.matcher(contact).matches(),
		InvalidParamException.class, "手机号码格式不正确");

	User userContact = getUserByContact(contact);
	AgAssert.isNull(userContact, UserExistContactException.class);

	User user = getUserByUserId(userId);
	AgAssert.notNull(user, EntityNotFoundException.class);
	AgAssert.isTrue(!isBindMobilePhoneNumber(user), SysTipsException.class,
		"该用户已经有绑定的手机号");

	User updateUser = new User();
	updateUser.setContact(contact);
	updateUser.setId(userId);
	return updateByPrimaryKeySelective(updateUser) > 0;
    }

    /**
     * 生成一个新用户
     * 
     * @param contact
     * @param password
     * @param appInfo
     * @return
     */
    private User generateUser(String contact, String password, String appInfo) {
	String realName = "";
	try {
	    realName = contact.substring(0, 3) + "****"
		    + contact.substring(contact.length() - 3, contact.length());
	} catch (Exception e) {
	    logger.error("根据手机号生产realName失败:" + e.getLocalizedMessage());
	}

	User newUser = new User();
	newUser.setContact(contact);
	newUser.setNickName(realName);//
	newUser.setPassword(password);
	newUser.setHeadImg(DEFAULT_HEAD_IMG);
	newUser.setRecordCreateTime(new Date().getTime() / 1000);

	return newUser;
    }

    /**
     * 注册一个新用户
     * 
     * @param contact
     * @param password
     * @param countyCode
     * @param isRoot
     * @return
     */
    @Transactional
    public User regist(String contact, String password, String appInfo) {

	if (StringUtils.isBlank(contact) || StringUtils.isBlank(password)) {
	    throw new InvalidParamException("手机号或者密码不能为空.");
	}

	User user = getUserByContact(contact);
	AgAssert.isNull(user, UserExistContactException.class);

	user = generateUser(contact, password, appInfo);

	boolean insert = insertSelective(user) > 0;
	Assert.isTrue(insert);

	return user;
    }

    /**
     * 微信注册用户
     * 
     * @param openId
     * @param realName
     * @param headImg
     * @param ext
     * @return
     */
    public User registFromWeixin(String openId, String realName,
	    String headImg, String ext) {
	return _registThirdLogin(StylistConstants.UserSource.WEIXIN, openId,
		realName, headImg, ext);
    }

    public User _registThirdLogin(int type, String pk, String realName,
	    String headImg, String ext) {
	if (NumberUtils.isNotValid(type) || StringUtils.isBlank(pk)
		|| StringUtils.isBlank(realName)) {
	    throw new InvalidParamException();
	}

	// ~=========== Start =======
	int newUserId = sequenceService.nextVal(SEQUENCE_USER_ID_KEY);
	User newUser = new User();
	newUser.setNickName(realName.replaceAll("[\\x{10000}-\\x{10FFFF}]", " "));
	newUser.setOpenSourceKey(pk);
	newUser.setPassword(RandomStringUtils.randomAlphanumeric(11));
	// newUser.setSex(1);
	newUser.setId(newUserId);
	// newUser.setCountyCode(XDMConstants.DEFAULT_AREACODE);
	newUser.setState(1);
	// newUser.setSources(type);
	newUser.setHeadImg(headImg);
	newUser.setRecordCreateTime(System.currentTimeMillis() / 1000);
	logger.info("new third User:" + newUser.getId());
	// ~=========== End =======
	boolean insert = insertSelective(newUser) > 0;
	timService.importAccount(newUser);

	userThirdPartyLoginService.addUserThirdPartyLogin(newUserId, pk, type,
		ext);
	//SpringUtils.publishEvent(new UserCreateEvent(newUser));
	return newUser;
    }

    /**
     * 更新登录记录
     * 
     * @param user
     * @param ip
     * @param deviceType
     * @param deviceName
     * @param appInfo
     * @return
     */
    public boolean doLoginRecord(User user, String ip, String deviceType,
	    String deviceName, String appInfo) {

	OperBuilder operBuilder = new OperBuilder(User.class);
	operBuilder.eq("loginIp", ip).eq("lastLoginIp", user.getLoginIp())
		.eq("loginTime", System.currentTimeMillis() / 1000)
		.eq("lastLoginTime", user.getLoginTime());
	// .eq("deviceType", deviceType).eq("deviceName", deviceName)

	Example example = example();
	example.createCriteria().andEqualTo("id", user.getId());
	return updateCustomOperByExample(operBuilder.get(), example) > 0;
    }

    /**
     * 更改性格
     * 
     * @param userId
     * @param newSex
     * @return
     */
    public boolean changeSex(Integer userId, Integer newSex) {
	User user = selectByPrimaryKey(userId);
	Assert.notNull(user);
	return changeSex(user, newSex);
    }

    /**
     * 更改性格
     * 
     * @param user
     * @param newSex
     * @return
     */
    public boolean changeSex(User user, Integer newSex) {
	if (NumberUtils.isNotValid(newSex)) {
	    throw new InvalidParamException();
	}

	// user.setSex(newSex);

	User updateUser = new User();
	// updateUser.setSex(newSex);
	updateUser.setId(user.getId());
	return updateByPrimaryKeySelective(updateUser) > 0;
    }

    /**
     * 更改姓名
     * 
     * @param userId
     * @param newHeadImg
     * @return
     */
    public boolean changeRealName(Integer userId, String newHeadImg) {
	User user = selectByPrimaryKey(userId);
	Assert.notNull(user);
	return changeRealName(user, newHeadImg);
    }

    public boolean changeRealName(User user, String newRealName) {
	if (StringUtils.isBlank(newRealName)) {
	    throw new InvalidParamException("昵称不能为空.");
	}

	if (newRealName.length() > 12) {
	    throw new SysTipsException("昵称长度不超过12个字符.");
	}

	user.setNickName(newRealName);

	User updateUser = new User();
	updateUser.setNickName(newRealName);
	updateUser.setId(user.getId());
	return updateByPrimaryKeySelective(updateUser) > 0;
    }

    /**
     * 更改头像
     * 
     * @param user
     * @param newHeadImg
     * @return
     */
    public boolean changeHeadImg(User user, String newHeadImg) {
	if (!StringUtils.equals(user.getHeadImg(), DEFAULT_HEAD_IMG)
		&& !StringUtils.equals(user.getHeadImg(), newHeadImg)) {
	    try {
		fileService.deleteFile(user.getHeadImg());
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	}

	user.setHeadImg(newHeadImg);

	User updateUser = selectByPrimaryKey(user.getId());
	updateUser.setHeadImg(newHeadImg);
	// updateUser.setId(user.getId());
	return updateByPrimaryKeySelective(updateUser) > 0;
    }

    /**
     * 重置秘密
     * 
     * @param userId
     * @param newPassword
     * @return
     */
    public boolean resetPassword(Integer userId, String newPassword) {
	User user = selectByPrimaryKey(userId);
	AgAssert.notNull(user, EntityNotFoundException.class, "找不到用户", userId);
	return resetPassword(user, newPassword);
    }

    /**
     * 重置秘密
     * 
     * @param user
     * @param newPassword
     * @return
     */
    public boolean resetPassword(User user, String newPassword) {
	AgAssert.notNull(user, UserContactNotFoundException.class);

	String newPasswordMD5 = AlgorithmUtils.encode(newPassword,
		AlgorithmEnum.MD5);
	if (StringUtils.equals(user.getPassword(), newPasswordMD5)) {
	    throw new SysTipsException("密码一致!");
	}

	user.setPassword(AlgorithmUtils.encode(newPassword, AlgorithmEnum.MD5));

	User updateUser = new User();
	updateUser.setPassword(user.getPassword());
	updateUser.setId(user.getId());
	return updateByPrimaryKeySelective(updateUser) > 0;
    }

    /**
     * 更改密码
     * 
     * @param userId
     * @param oldPassword
     * @param newPassword
     * @return
     */
    public boolean changePassword(Integer userId, String oldPassword,
	    String newPassword) {
	User user = selectByPrimaryKey(userId);
	Assert.notNull(user);
	return changePassword(user, oldPassword, newPassword);
    }

    public boolean changePassword(User user, String oldPassword,
	    String newPassword) {

	if (StringUtils.isBlank(oldPassword)
		|| StringUtils.isBlank(newPassword)) {
	    throw new InvalidParamException();
	}

	if (StringUtils.equals(newPassword, oldPassword)) {
	    throw new SysTipsException("新密码和旧密码重复!");
	}

	String oldPasswordMD5 = AlgorithmUtils.encode(oldPassword,
		AlgorithmEnum.MD5);
	if (!StringUtils.equals(oldPasswordMD5, user.getPassword())) {
	    throw new SysTipsException("原始密码不一致!");
	}

	String newPasswordMD5 = AlgorithmUtils.encode(newPassword,
		AlgorithmEnum.MD5);
	user.setPassword(newPasswordMD5);

	User updateUser = new User();
	updateUser.setPassword(user.getPassword());
	updateUser.setId(user.getId());
	return updateByPrimaryKeySelective(updateUser) > 0;
    }

    @Override
    protected IDao<User> getIDao() {
	return mapper;
    }

    /**
     * 查找当前用户编号中的设备类型
     */
    public List<Map<String, Object>> queryUserListDeviceType(
	    List<Integer> userIds) {

	List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
	if (null != userIds && userIds.size() > 0) {
	    Example example = example();
	    Criteria criteria = example.createCriteria();
	    criteria.andIn(User.PROPERTY_ID, userIds);
	    List<User> list = selectByExample(example);
	    if (null != list && list.size() > 0) {
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
		    User user = (User) iterator.next();
		    Map<String, Object> map = new HashMap<String, Object>();
		    map.put(User.PROPERTY_ID, user.getId());
		    resultList.add(map);
		}
	    }
	}
	return resultList;
    }

    public IUserExtMapper getUserExtMapper() {
	return userExtMapper;
    }

    public void setUserExtMapper(IUserExtMapper userExtMapper) {
	this.userExtMapper = userExtMapper;
    }

}